/*************************************************************************
* Copyright (C) 2024 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

/*!
  *
  *  \file
  *
  *  \brief Leighton-Micali Hash-Based Signatures (LMS) example
  *
  *  This example demonstrates usage of LMS signatures verification.
  *
  *  The LMS algorithm is implemented according to the
  *  "Leighton-Micali Hash-Based Signatures" document:
  *
  *  https://datatracker.ietf.org/doc/html/rfc8554
  *
  */

/*! Define the macro to enable LMS usage */
#define IPPCP_PREVIEW_LMS

#include <memory>

#include "ippcp.h"
#include "examples_common.h"


/*! Algorithm ID for LMS */
IppsLMSAlgo lmsAlgo = IppsLMSAlgo::LMS_SHA256_M32_H5; //0x00000005

/*! Algorithm ID for OTS (one-time signature) */
IppsLMOTSAlgo lmotsAlgo = IppsLMOTSAlgo::LMOTS_SHA256_N32_W8; //0x00000004

/*! Index of the LMS leaf */
static Ipp32u q = 0x00000009;

/*! Pointer to the LMS private key identifier */
static Ipp8u pI[]        = { 0x05,0xbd,0x3d,0x90,0xcc,0xa2,0x47,0x08,0xe4,0x20,0x55,0x3e,0x5a,0xf7,0xb9,0xc8 };

/*! Pointer to the LMS public key */
static Ipp8u pK[]        = { 0x21,0xf9,0xd9,0x09,0x97,0x11,0xef,0x5b,0x14,0x50,0x0b,0x6a,0x18,0x1e,0x73,0x9e,
                             0xd3,0x12,0x74,0xdb,0x72,0xac,0xe7,0xcf,0x29,0x32,0x9a,0x45,0xe8,0xde,0x11,0xfe };

/*! Message */
static Ipp8u pMsg[]       = { 0x04,0x3d,0x64,0x00,0x10,0x3b,0x16,0x0c,0xf1,0x89,0xb4,0xcf,0xff,0x08,0x06,0xfe,
                             0xe3,0xe1,0x56,0x7f,0x2c,0x31,0x71,0x0f,0x82,0x84,0x52,0x74,0xf6,0xed,0x23,0x8e,
                             0x14,0xde,0x4d,0x53,0x99,0x86,0x88,0x99,0xab,0x6b,0xcf,0x00,0x98,0x08,0xb8,0xca,
                             0x30,0x81,0xed,0x11,0xaa,0x70,0x35,0x52,0x90,0xfd,0x86,0x98,0xd4,0xc1,0x77,0xc1,
                             0x89,0x4c,0xd8,0xb8,0xd3,0x36,0x7f,0xd0,0xf3,0x00,0xef,0x62,0x83,0x02,0x0d,0x09,
                             0x1c,0x27,0x35,0x6d,0xaf,0xad,0xdb,0xed,0x96,0x21,0x8a,0x19,0x56,0x7b,0x99,0x9a,
                             0xcd,0x53,0x02,0xa5,0x11,0xd4,0xf1,0x65,0xef,0x9c,0xbe,0x85,0x5d,0xcc,0x73,0x1b,
                             0x16,0xdd,0x13,0x6e,0x5c,0x44,0x15,0x8b,0xf1,0xe9,0x8c,0xc5,0x9c,0x6f,0x6c,0xb2 };

/*! Pointer to the C LM-OTS value */
static Ipp8u pC[]        = { 0x67,0x79,0x57,0x17,0x51,0x05,0x2c,0xe8,0xfe,0xe9,0x23,0xda,0x26,0xef,0x27,0x1e,
                             0x62,0xbe,0x08,0x43,0xaa,0xdf,0x7c,0x69,0x19,0x68,0x43,0x32,0x8c,0xb0,0x4e,0x3d };

/*! Pointer to the y LM-OTS value */
static Ipp8u pY[]        = { 0x57,0x71,0xa7,0x12,0x2b,0x87,0xf2,0xbd,0x61,0x11,0x9c,0xd4,0x20,0x56,0xec,0x04,
                             0xc0,0x60,0xbe,0x2a,0xe2,0xc2,0xd6,0x72,0xa8,0x1f,0x1a,0x4a,0x6a,0x76,0xc2,0x4c,
                             0x01,0xa0,0x69,0x63,0x7f,0x85,0xdd,0xb4,0x5d,0x8d,0x19,0xd7,0xef,0x7c,0xc8,0x9a,
                             0x47,0xfe,0x1e,0x79,0xfd,0x80,0x65,0x51,0x17,0xed,0xb6,0x3f,0x17,0xd0,0xb6,0xcc,
                             0x0f,0xca,0xa9,0x28,0xc2,0xef,0x1e,0x41,0x4e,0xf7,0x34,0xa8,0xda,0xfe,0xbc,0x82,
                             0xdb,0x33,0x3e,0x03,0xba,0x51,0x40,0x6e,0x07,0x6b,0xfc,0x2d,0x3e,0x81,0x30,0x09,
                             0xd9,0x68,0xa8,0x71,0x00,0xf0,0x33,0xcf,0x0b,0x57,0x04,0xfc,0x4e,0x61,0x8a,0xa5,
                             0x80,0xa1,0xe0,0x48,0xef,0xc3,0xd5,0x6e,0xe7,0xa2,0xea,0x02,0x14,0xa6,0xfe,0x1f,
                             0x39,0xa4,0xf2,0xfb,0x61,0x2f,0x44,0xbe,0xde,0xd3,0x73,0x34,0x0e,0x76,0x48,0x27,
                             0xc5,0xc5,0x8c,0xb9,0x07,0xcd,0x08,0xdd,0xfb,0xde,0x01,0xbb,0x11,0xff,0x3a,0x89,
                             0xff,0xaa,0xd8,0xcd,0x7c,0x17,0x02,0x71,0x08,0x3c,0xe5,0x0f,0x0f,0xb9,0xea,0xbb,
                             0xa8,0x9d,0xb6,0x0b,0x00,0x73,0xe7,0xaf,0xc8,0x1e,0x4c,0x6f,0x82,0x4a,0xef,0x09,
                             0xf8,0xbf,0xc9,0x49,0x67,0x16,0x9b,0xcf,0xa0,0x84,0x76,0x55,0x57,0x41,0x10,0x19,
                             0x37,0x0b,0x29,0xba,0x0d,0x32,0xa8,0x8e,0x84,0x2c,0x19,0xdf,0x14,0x5a,0x69,0x36,
                             0x8d,0xf7,0xe1,0x55,0x7d,0x93,0x7a,0xae,0xdb,0x07,0xf6,0xbc,0xda,0xf9,0x78,0xeb,
                             0x9e,0x50,0xf3,0xc8,0x47,0x38,0x2a,0xd4,0x3b,0xfc,0xc0,0xe0,0xd0,0xbf,0xd8,0x60,
                             0x46,0x63,0xc7,0xfb,0xa8,0x84,0x45,0x4d,0x23,0x98,0x96,0xd8,0xff,0x8a,0x99,0xa3,
                             0x34,0xf0,0xd3,0x32,0x22,0xaa,0x15,0xbd,0x47,0x9f,0xcd,0x49,0x52,0x0b,0x5b,0x2d,
                             0x83,0xd8,0xbf,0x4d,0xbd,0x3d,0x7e,0x9d,0xc8,0x0b,0x62,0x0c,0xc7,0x03,0x45,0x7f,
                             0x55,0x90,0x35,0xdd,0x1f,0x53,0xdc,0xec,0x0b,0x4d,0x89,0xca,0xb1,0xa3,0xb8,0x87,
                             0x7b,0x31,0x1c,0x24,0x90,0x44,0x9d,0xf7,0xa6,0x1c,0xf8,0xed,0xf3,0x29,0xd6,0x96,
                             0x26,0xca,0x42,0x4b,0xdf,0x61,0x00,0x91,0x92,0x08,0x37,0x76,0xbb,0x96,0x9e,0xd5,
                             0x8d,0x76,0xa9,0x52,0x40,0xdb,0x3f,0xd6,0xec,0xa0,0x06,0x89,0x88,0x11,0x18,0x38,
                             0xae,0xcb,0xa0,0x71,0xab,0x3b,0x7b,0xe0,0x94,0x30,0x59,0x38,0xaf,0xb0,0x8c,0xdd,
                             0xf9,0xcd,0xaf,0x82,0x49,0x90,0x29,0xf6,0x24,0x9a,0xa5,0x51,0x1b,0x99,0x45,0x64,
                             0x13,0x94,0x9e,0x3e,0x4e,0x43,0x40,0x73,0x0d,0x68,0x0b,0x68,0xde,0xb5,0xc9,0xd5,
                             0xce,0xef,0x7b,0x8b,0x1e,0xd9,0x7e,0xc8,0xa1,0x69,0xb5,0x2b,0xd0,0x54,0xb0,0x53,
                             0x41,0x9f,0xfa,0x77,0x34,0x55,0xcd,0xf4,0x79,0xa6,0x0d,0x3c,0xc7,0x05,0xd8,0xf2,
                             0x08,0x48,0x32,0xb7,0x96,0x22,0xb6,0xe5,0xac,0x83,0x06,0xa7,0x68,0x3f,0xea,0x03,
                             0xcd,0x79,0xe8,0xff,0x54,0xe2,0xf5,0xa0,0x6b,0x69,0xc1,0xca,0xb3,0xd4,0x2b,0x60,
                             0xa8,0xa8,0xbe,0xcb,0x9e,0x94,0x2e,0xf1,0xfc,0xd7,0x55,0xac,0x08,0xd7,0xc4,0x22,
                             0x4f,0xf3,0xf5,0xbf,0x49,0xb8,0xf7,0x5f,0xae,0x60,0x92,0xe4,0x3a,0x8f,0x30,0x35,
                             0x41,0x8c,0xd4,0x03,0x31,0x6c,0x08,0xa8,0x08,0x37,0xb4,0x6c,0x22,0xca,0xa2,0xf7,
                             0xff,0xc1,0x62,0x49,0xcd,0x5c,0x17,0x25,0xc5,0x4e,0xaa,0x26,0xb9,0xd7,0x72,0xf9,
                             0x61,0x21,0xbf,0x95,0xda,0xcf,0x30,0x1d,0x42,0x8c,0x9d,0xf4,0x57,0x36,0x25,0xb7,
                             0xfb,0xfa,0x64,0xba,0x7f,0x3e,0x0d,0x5a,0x72,0xa7,0x8d,0x13,0xf6,0x2d,0x57,0x76,
                             0xa4,0x61,0x59,0x9d,0x4d,0xd5,0x99,0x0e,0xae,0x73,0x6b,0x6a,0xf1,0x64,0x93,0xf1,
                             0xa7,0xd0,0xe4,0x4f,0x2b,0x71,0xd9,0x6e,0x0e,0x89,0x28,0x5a,0xec,0xc1,0x15,0x50,
                             0x81,0x21,0x6c,0xe0,0xba,0xbb,0xce,0x4f,0x4e,0x0b,0x80,0xa1,0x92,0x6a,0xea,0x6a,
                             0xcb,0x3e,0xa3,0xcb,0x7a,0x23,0x61,0x5d,0x41,0x08,0xba,0xf4,0x51,0x9b,0xf7,0x10,
                             0x27,0x0e,0x89,0x6b,0x42,0xc5,0x5c,0x3c,0x9e,0x60,0x42,0x43,0x29,0xbf,0xbc,0x8a,
                             0xd5,0x9f,0x4c,0xa2,0x0b,0x5e,0xbb,0xa4,0x93,0xe0,0xb3,0x9d,0xb9,0x7e,0xc7,0x9b,
                             0x36,0x2a,0xc7,0x21,0x5e,0x25,0x5d,0xeb,0x74,0x68,0xfd,0xf4,0x0e,0x0f,0x39,0x0c,
                             0x65,0x0c,0x66,0x51,0x0c,0xf4,0xad,0x9c,0x44,0x94,0x34,0xae,0x25,0x8b,0x56,0x1e,
                             0x8e,0xc1,0x57,0x29,0xa6,0x90,0x62,0xb8,0xb2,0x8d,0x6c,0x79,0xf4,0x90,0x64,0xd2,
                             0x4a,0x52,0xe9,0x15,0x95,0xc9,0x3f,0x83,0xc4,0x0f,0xec,0xa2,0x11,0xe2,0x8b,0x50,
                             0x1f,0x13,0xcc,0x80,0x2f,0x0b,0x36,0x35,0x2c,0x85,0x41,0x79,0xd2,0xce,0x46,0x12,
                             0xc7,0xf0,0xd3,0x96,0x04,0x4d,0x1c,0x69,0x4f,0x8f,0xe3,0xa0,0x1c,0xe2,0xa8,0x8c,
                             0xe8,0xd1,0x74,0xca,0x66,0x99,0x1b,0x9d,0x6c,0x50,0x72,0xf2,0xd2,0x01,0x60,0xdf,
                             0x74,0x81,0xaf,0xbd,0x7a,0xc9,0xd2,0xf7,0x5a,0x7d,0xfe,0x36,0x9c,0x61,0xed,0xc9,
                             0xfb,0x27,0xbb,0xa3,0xd8,0x71,0x3c,0x57,0x5d,0xdd,0xab,0xcc,0x27,0xc6,0xb9,0x42,
                             0x9b,0xcb,0x7e,0xec,0xf8,0x53,0x2e,0xf0,0xf4,0xc9,0x46,0x46,0xd8,0x94,0xd6,0xf7,
                             0x8d,0x64,0xd7,0xba,0xb1,0x39,0x8e,0x7f,0xef,0xfd,0xb0,0xb0,0x31,0x4f,0x43,0x0f,
                             0xec,0xa8,0x70,0x57,0x3a,0xe3,0x88,0xbc,0xa7,0xd9,0xf9,0x39,0xa4,0xb9,0x91,0x59,
                             0xc7,0xbf,0xec,0x78,0xa9,0xce,0x33,0x99,0xf3,0x83,0xfa,0xaf,0x59,0xab,0x65,0xc6,
                             0xe2,0xaa,0x30,0x08,0xd7,0x99,0x71,0x65,0xf1,0xb6,0xfc,0x4f,0xf1,0x68,0xa2,0xd8,
                             0x61,0x8a,0xe5,0x0f,0x2b,0x60,0xda,0x8d,0xea,0x7e,0xf6,0x2c,0xae,0xeb,0x26,0xae,
                             0x29,0x5d,0xab,0xc7,0x3f,0x27,0x2c,0x51,0xf1,0x3f,0x22,0x22,0xef,0x52,0x4e,0xcb,
                             0x70,0xd8,0xba,0x41,0x53,0xb4,0xd9,0xdd,0xdc,0xe8,0xcd,0x7f,0xc1,0xb8,0x2b,0x8e,
                             0x3b,0x3b,0x86,0xd7,0x4c,0x36,0x69,0xf6,0x31,0xcf,0x37,0xbd,0x16,0xe9,0x2f,0x4f,
                             0xf9,0x13,0x19,0xf2,0x3b,0x41,0x1c,0x78,0x62,0x9c,0x5f,0x95,0xab,0xdd,0x17,0xe7,
                             0x2e,0x8f,0x92,0x79,0xe0,0xeb,0xe0,0x49,0x58,0x6d,0x3c,0x26,0xb8,0x5c,0x93,0xb9,
                             0xd7,0x6e,0xca,0x28,0x70,0x9c,0xbe,0xef,0x08,0x4e,0xe2,0x20,0x3a,0xdb,0x92,0x0b,
                             0x29,0x2f,0xfd,0xc8,0x3a,0x4a,0x7c,0xa4,0x87,0x6f,0x33,0x8d,0x8e,0x7f,0x51,0x6f,
                             0xab,0x11,0x42,0xc3,0x75,0xed,0x69,0xb1,0xf1,0x32,0xd8,0xd8,0xe2,0xc2,0x0d,0x52,
                             0x21,0xad,0x97,0x05,0x60,0x1d,0x43,0x52,0x4c,0xb1,0x61,0x49,0xef,0x2c,0xc1,0xad,
                             0x4c,0x0c,0xe7,0x1b,0x81,0xc6,0x2f,0x47,0xe2,0xb0,0xe6,0x6c,0xb8,0xd0,0x2d,0xe4,
                             0x46,0xd2,0x0a,0x13,0xab,0xb3,0xb9,0x13,0x9e,0x41,0xba,0x06,0x2d,0x11,0xe4,0xe6 };

/*! Pointer to the LMS authorization path */
static Ipp8u pAuthPath[] = { 0xc7,0x14,0x06,0x72,0xbf,0x82,0x00,0x91,0xe3,0xd5,0xd6,0x4c,0x2a,0x71,0x21,0x83,
                             0x3b,0xea,0xb1,0x16,0x74,0xd8,0xae,0x4e,0xe3,0x15,0xe7,0x85,0x4d,0xa7,0xa1,0x00,
                             0x4b,0x2b,0x7b,0xc6,0xad,0x89,0xa8,0x6c,0xe8,0xf6,0x60,0x22,0x19,0xb9,0xc3,0x37,
                             0x5b,0xca,0x93,0xf1,0x0e,0xa3,0x2f,0x10,0xfb,0x2f,0x39,0x21,0x1c,0x33,0x78,0xb7,
                             0x89,0x0f,0x77,0x18,0xe8,0x73,0x04,0x54,0x71,0x08,0x0b,0x86,0x94,0x9e,0xc7,0x55,
                             0x25,0xb9,0x4a,0xe1,0xbb,0x45,0x06,0x00,0x66,0xdf,0x75,0x17,0x8b,0x0d,0xc3,0xa6,
                             0x65,0x9a,0x5e,0xc7,0x5d,0xe5,0xc1,0x29,0x1f,0x5f,0xfc,0xcb,0x89,0x84,0x5c,0xfb,
                             0x7a,0x81,0xe2,0x54,0x05,0xd1,0x90,0xe3,0x7d,0xe4,0x3c,0x9f,0xe2,0xdc,0xd3,0xfd,
                             0x7e,0x6e,0x72,0xfa,0xc7,0xbe,0xcb,0xd5,0xd0,0x1e,0xc4,0xae,0x48,0x9a,0x92,0x45,
                             0xc3,0xc2,0xc1,0x06,0x91,0xbe,0x15,0x1f,0xa6,0xa1,0x87,0xbb,0x7c,0x68,0x7b,0xb8 };

int main(void)
{
    /* Internal function status */
    IppStatus status = ippStsNoErr;

    /* Deleter to use in unique_ptr to clean the memory during the object's destruction */
    auto toIpp8uDeleter = [] (auto* pData) { delete[] (Ipp8u*)pData; };

    const Ipp32s msgLen = sizeof(pMsg);

    /* Create an algorithm ID to put into the ippsLMS functions */
    const IppsLMSAlgoType lmsAlgTypePk = { lmotsAlgo, lmsAlgo };

    /* 1. Get the scratch buffer size */
    int buffSize;
    status = ippsLMSBufferGetSize(&buffSize, msgLen, lmsAlgTypePk);
    if (!checkStatus("ippsLMSBufferGetSize", ippStsNoErr, status))
        return status;
    /* 2. Allocate memory for the scratch buffer */
    std::unique_ptr<Ipp8u> pScratchBuffer(new Ipp8u[buffSize]);

    /* 3. Get the LMS public key state size */
    int ippcpPubKeySize;
    status = ippsLMSPublicKeyStateGetSize(&ippcpPubKeySize, lmsAlgTypePk);
    if (!checkStatus("ippsLMSPublicKeyStateGetSize", ippStsNoErr, status))
        return status;

    /* 4. Allocate memory for the LMS public key state */
    std::unique_ptr<IppsLMSPublicKeyState, decltype(toIpp8uDeleter)>
                    pPubKey((IppsLMSPublicKeyState *)(new Ipp8u[ippcpPubKeySize]), toIpp8uDeleter);

    /* 5. Set the LMS public key */
    status = ippsLMSSetPublicKeyState(lmsAlgTypePk, pI, pK, pPubKey.get());
    if (!checkStatus("ippsLMSSetPublicKeyState", ippStsNoErr, status))
        return status;

    /* 6. Get the LMS signature state size */
    int sigBuffSize;
    status = ippsLMSSignatureStateGetSize(&sigBuffSize, lmsAlgTypePk);
    if (!checkStatus("ippsLMSSignatureStateGetSize", ippStsNoErr, status))
        return status;

    /* 7. Allocate memory for the LMS signature buffer */
    std::unique_ptr<IppsLMSSignatureState, decltype(toIpp8uDeleter)>
                   pSignature((IppsLMSSignatureState *)(new Ipp8u[sigBuffSize]), toIpp8uDeleter);

    /* 8. Set the LMS signature */
    status = ippsLMSSetSignatureState(lmsAlgTypePk, q, pC, pY, pAuthPath, pSignature.get());
    if (!checkStatus("ippsLMSSetSignatureState", ippStsNoErr, status))
        return status;

    int is_valid = 0;
    /* 9. Verify the LMS signature */
    status = ippsLMSVerify(pMsg, msgLen, pSignature.get(), &is_valid, pPubKey.get(), pScratchBuffer.get());
    if (!checkStatus("ippsLMSVerify", ippStsNoErr, status))
        return status;

    PRINT_EXAMPLE_STATUS("ippsLMSVerify", "LMS Verification", 1 == is_valid);

    return status;
}
